home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / du.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  5KB  |  238 lines

  1. /* du - report on disk usage        Author: Alistair G. Crooks */
  2.  
  3. /*
  4.  *    du.c        1.1    27/5/87        agc    Joypace Ltd.
  5.  *            1.2    24 Mar 89    nick@nswitgould.oz
  6.  *            1.3    31 Mar 89    nick@nswitgould.oz
  7.  *            1.4    22 Feb 90    meulenbr@cst.prl.philips.nl
  8.  *
  9.  *    Copyright 1987, Joypace Ltd., London UK. All rights reserved.
  10.  *    This code may be freely distributed, provided that this notice
  11.  *    remains attached.
  12.  *
  13.  *    du - a public domain interpretation of du(1).
  14.  *
  15.  *  1.2:     Fixed bug involving 14 character long filenames
  16.  *  1.3:    Add [-l levels] option to restrict printing.
  17.  *  1.4:    Added processing of multiple arguments
  18.  *
  19.  */
  20.  
  21.  
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <fcntl.h>
  25. #include <blocksize.h>
  26. #include <stdio.h>
  27.  
  28. char *prog;            /* program name */
  29. char *optstr = "asl:";        /* -a and -s arguments */
  30. int silent = 0;            /* silent mode */
  31. int all = 0;            /* all directory entries mode */
  32. char *startdir = ".";        /* starting from here */
  33. int levels = 255;        /* # of directory levels to print */
  34.  
  35. #define    LINELEN 256
  36.  
  37. #define DIRNAMELEN 14
  38. #define    LSTAT stat
  39. typedef struct _dirstr {
  40.   ino_t inum;
  41.   char d_name[DIRNAMELEN];
  42. } DIR;
  43. DIR dir;
  44.  
  45. typedef struct _alstr {
  46.   int al_dev;
  47.   ino_t al_inum;
  48. } ALREADY;
  49.  
  50. #define    MAXALREADY    50
  51. ALREADY already[MAXALREADY];
  52. int alc = 0;
  53.  
  54. /*
  55.  *    myindex - stop the scanf bug
  56.  */
  57. char *myindex(s, c)
  58. register char *s;
  59. register char c;
  60. {
  61.   for (; *s; s++)
  62.     if (*s == c) return(s);
  63.   return(NULL);
  64. }
  65.  
  66.  
  67. /*
  68.  *    getopt - parse the arguments given.
  69.  *    retrieved from net.sources
  70.  */
  71. int opterr = 1;
  72. int optind = 1;
  73. int optopt;
  74. char *optarg;
  75.  
  76. #define BADCH    (int)'?'
  77. #define EMSG    ""
  78. #define TELL(s)    fputs(*nargv, stderr); fputs(s, stderr);\
  79.   fputc(optopt, stderr); fputc('\n', stderr);\
  80.   return(BADCH);
  81.  
  82. int getopt(nargc, nargv, ostr)
  83. int nargc;
  84. char **nargv;
  85. char *ostr;
  86. {
  87.   register char *oli;
  88.   static char *place = EMSG;
  89.  
  90.   if (!*place) {
  91.     if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place)
  92.         return(EOF);
  93.     if (*place == '-') {
  94.         ++optind;
  95.         return(EOF);
  96.     }
  97.   }
  98.   if ((optopt = (int) *place++) == (int) ':' || !(oli = myindex(ostr, optopt))) {
  99.     if (!*place) ++optind;
  100.     TELL(": illegal option -- ");
  101.   }
  102.   if (*++oli != ':') {
  103.     optarg = NULL;
  104.     if (!*place) ++optind;
  105.   } else {
  106.     if (*place)
  107.         optarg = place;
  108.     else if (nargc <= ++optind) {
  109.         place = EMSG;
  110.         TELL(": option requires an argument -- ");
  111.     } else
  112.         optarg = nargv[optind];
  113.     place = EMSG;
  114.     ++optind;
  115.   }
  116.   return(optopt);
  117. }
  118.  
  119. /*
  120.  *    makedname - make the pathname from the directory name, and the
  121.  *    directory entry, placing it in out. If this would overflow,
  122.  *    return 0, otherwise 1.
  123.  */
  124. int makedname(d, f, out, outlen)
  125. char *d;
  126. char *f;
  127. char *out;
  128. int outlen;
  129. {
  130.   char *cp;
  131.   int length;
  132.  
  133.   /* Find length (1-14) of directory entry */
  134.   cp = f;
  135.   for (length = 0; *cp && (length < 14); ++cp) ++length;
  136.  
  137.   if (strlen(d) + length + 2 > outlen) return(0);
  138.   for (cp = out; *d; *cp++ = *d++);
  139.   if (*(cp - 1) != '/') *cp++ = '/';
  140.   while (length--) *cp++ = *f++;
  141.   *cp = '\0';
  142.   return(1);
  143. }
  144.  
  145. /*
  146.  *    done - have we encountered (dev, inum) before? Returns 1 for yes,
  147.  *    0 for no, and remembers (dev, inum).
  148.  */
  149. int done(dev, inum)
  150. int dev;
  151. ino_t inum;
  152. {
  153.   register ALREADY *ap;
  154.   register int i;
  155.   int ret = 0;
  156.  
  157.   for (i = 0, ap = already; i < alc; ap++, i++)
  158.     if (ap->al_dev == dev && ap->al_inum == inum) {
  159.         ret = 1;
  160.         break;
  161.     }
  162.   if (alc < MAXALREADY) {
  163.     already[alc].al_dev = dev;
  164.     already[alc++].al_inum = inum;
  165.   }
  166.   return(ret);
  167. }
  168.  
  169. /*
  170.  *    dodir - process the directory d. Return the long size (in blocks)
  171.  *    of d and its descendants.
  172.  */
  173. long dodir(d, thislev)
  174. char *d;
  175. int thislev;
  176. {
  177.   struct stat s;
  178.   long total = 0L;
  179.   char dent[LINELEN];
  180.   int fd;
  181.  
  182.   if ((fd = open(d, O_RDONLY)) < 0) return(0L);
  183.   while (read(fd, &dir, sizeof(dir)) > 0) {
  184.     if (strcmp(dir.d_name, ".") == 0 ||
  185.         strcmp(dir.d_name, "..") == 0)
  186.         continue;
  187.     if (dir.inum == 0) continue;
  188.     if (!makedname(d, dir.d_name, dent, sizeof(dent))) continue;
  189.     if (LSTAT(dent, &s) < 0) continue;
  190.     if (s.st_nlink > 1 && done(s.st_dev, s.st_ino)) continue;
  191.     if ((s.st_mode & S_IFMT) == S_IFDIR)
  192.         total += dodir(dent, thislev - 1);
  193.     switch (s.st_mode & S_IFMT) {
  194.         case S_IFREG:
  195.         case S_IFDIR:
  196.         total += (s.st_size + BLOCK_SIZE) / BLOCK_SIZE;
  197.         break;
  198.     }
  199.     if (all && (s.st_mode & S_IFMT) != S_IFDIR)
  200.         if (thislev > 0)    /* this is correct - file in subdir */
  201.             printf("%ld\t%s\n",
  202.                 (s.st_size + BLOCK_SIZE) / BLOCK_SIZE, dent);
  203.   }
  204.   close(fd);
  205.   if (!silent)
  206.     if (thislev >= 0)    /* this is correct - subdir itself */
  207.         printf("%ld\t%s\n", total, d);
  208.   return(total);
  209. }
  210.  
  211. /*
  212.  *    OK, here goes...
  213.  */
  214. main(argc, argv)
  215. int argc;
  216. char **argv;
  217. {
  218.   long tot;
  219.   int c;
  220.  
  221.   prog = argv[0];
  222.   while ((c = getopt(argc, argv, optstr)) != EOF) switch (c) {
  223.         case 'a':    all = 1;    break;
  224.         case 's':    silent = 1;    break;
  225.         case 'l':    levels = atoi(optarg);    break;
  226.         default:
  227.         fprintf(stderr,
  228.             "Usage: %s [-a] [-s] [-l levels] [startdir]\n", prog);
  229.         exit(1);
  230.     }
  231.   do {
  232.     if (optind < argc) startdir = argv[optind++];
  233.     tot = dodir(startdir, levels);
  234.     if (silent) printf("%ld\t%s\n", tot, startdir);
  235.   } while (optind < argc);
  236.   exit(0);
  237. }
  238.